home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / unix / volume16 / spiff / part03 < prev    next >
Encoding:
Internet Message Format  |  1988-11-10  |  47.6 KB

  1. Subject:  v16i069:  Spiff, find approximate differences in files, Part03/04
  2. Newsgroups: comp.sources.unix
  3. Sender: sources
  4. Approved: rsalz@uunet.UU.NET
  5.  
  6. Submitted-by: Daniel W Nachbar <daniel@wind.bellcore.com>
  7. Posting-number: Volume 16, Issue 69
  8. Archive-name: spiff/part03
  9.  
  10. #! /bin/sh
  11. # This is a shell archive.  Remove anything before this line, then unpack
  12. # it by saving it into a file and typing "sh file".  To overwrite existing
  13. # files, type "sh file -c".  You can also feed this as standard input via
  14. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  15. # will see the following message at the end:
  16. #        "End of archive 3 (of 4)."
  17. # Contents:  float.c parse.c spiff.1
  18. # Wrapped by rsalz@papaya.bbn.com on Fri Nov 11 13:12:26 1988
  19. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  20. if test -f 'float.c' -a "${1}" != "-c" ; then 
  21.   echo shar: Will not clobber existing file \"'float.c'\"
  22. else
  23. echo shar: Extracting \"'float.c'\" \(13078 characters\)
  24. sed "s/^X//" >'float.c' <<'END_OF_FILE'
  25. X/*                        Copyright (c) 1988 Bellcore
  26. X**                            All Rights Reserved
  27. X**       Permission is granted to copy or use this program, EXCEPT that it
  28. X**       may not be sold for profit, the copyright notice must be reproduced
  29. X**       on copies, and credit should be given to Bellcore where it is due.
  30. X**       BELLCORE MAKES NO WARRANTY AND ACCEPTS NO LIABILITY FOR THIS PROGRAM.
  31. X*/
  32. X
  33. X
  34. X#ifndef lint
  35. Xstatic char rcsid[]= "$Header: float.c,v 1.1 88/09/15 11:33:53 daniel Rel $";
  36. X#endif
  37. X
  38. X#include <ctype.h>
  39. X#include "misc.h"
  40. X#include "floatrep.h"
  41. X#include "float.h"
  42. X#include "strings.h"
  43. X
  44. X#define _F_GETEND(x)    (x + (strlen(x)-1)) 
  45. X
  46. X/*
  47. Xint floatcnt = 0;
  48. X*/
  49. X/*
  50. X**    routines to convert strings to our internal floating point form
  51. X**        isfloat just looks at the string
  52. X**        to see if a conversion is reasonable
  53. X**            it does look-ahead on when it sees an 'e' and such.
  54. X**        atocf actually does the conversion.
  55. X**    these two routines could probably be combined
  56. X*/
  57. X
  58. X/*
  59. X**    test to see if the string can reasonably
  60. X**        be interpreted as floating point number
  61. X**    returns 0 if string can't be interpreted as a float
  62. X**    otherwise returns the number of digits that will be used in F_atof
  63. X*/
  64. XF_isfloat(str,need_decimal,allow_sign)
  65. Xchar *str;
  66. Xint need_decimal;    /* if non-zero, require that a decimal point be present
  67. X                otherwise, accept strings like "123" */
  68. Xint allow_sign;        /* if non-zero, allow + or - to set the sign */
  69. X{
  70. X    int man_length = 0;    /* length of the fractional part (mantissa) */
  71. X    int exp_length = 0;    /* length of the exponential part */
  72. X    int got_a_digit = 0;    /* flag to set if we ever see a digit */
  73. X
  74. X    /*
  75. X    **    look for an optional leading sign marker
  76. X    */
  77. X    if (allow_sign && ('+' == *str  || '-' == *str))
  78. X    {
  79. X        str++; man_length++;
  80. X    }
  81. X    /*
  82. X    **    count up the digits on the left hand side
  83. X    **         of the decimal point
  84. X    */
  85. X    while(isdigit(*str))
  86. X    {
  87. X        got_a_digit = 1;
  88. X        str++; man_length++;
  89. X    }
  90. X
  91. X    /*
  92. X    **    check for a decimal point
  93. X    */
  94. X    if ('.' == *str)
  95. X    {
  96. X        str++; man_length++;
  97. X    }
  98. X    else
  99. X    {
  100. X        if (need_decimal)
  101. X        {
  102. X            return(0);
  103. X        }
  104. X    }
  105. X
  106. X    /*
  107. X    **    collect the digits on the right hand
  108. X    **        side of the decimal point
  109. X    */
  110. X    while(isdigit(*str))
  111. X    {
  112. X        got_a_digit = 1;
  113. X        str++; man_length++;
  114. X    }
  115. X
  116. X    if (!got_a_digit)
  117. X        return(0);
  118. X
  119. X    /*
  120. X    **    now look ahead for an exponent
  121. X    */
  122. X    if ('e' == *str ||
  123. X        'E' == *str ||
  124. X        'd' == *str ||
  125. X        'D' == *str)
  126. X    {
  127. X        str++; exp_length++;
  128. X        if ('+' == *str  || '-' == *str)
  129. X        {
  130. X            str++; exp_length++;
  131. X        }
  132. X
  133. X        if (!isdigit(*str))
  134. X        {
  135. X            /*
  136. X            **    look ahead went too far,
  137. X            **    so return just the length of the mantissa
  138. X            */
  139. X            return(man_length);
  140. X        }
  141. X
  142. X        while (isdigit(*str))
  143. X        {
  144. X            str++; exp_length++;
  145. X        }
  146. X    }
  147. X    return(man_length+exp_length);    /* return the total length */
  148. X}
  149. X
  150. X/*
  151. X**    routine to convert a string to our internal
  152. X**    floating point representation
  153. X**
  154. X**        similar to atof()
  155. X*/
  156. XF_float
  157. XF_atof(str,allflag)
  158. Xchar *str;
  159. Xint allflag;    /* require that exactly all the characters are used */
  160. X{
  161. X    char *beg = str; /* place holder for beginning of the string */ 
  162. X    char man[R_MANMAX];    /* temporary location to build the mantissa */
  163. X    int length = 0;    /* length of the mantissa so far */
  164. X    int got_a_digit = 0;    /* flag to set if we get a non-zero digit */ 
  165. X    int i;
  166. X    int resexp;
  167. X
  168. X    F_float res;    /* where we build the result */
  169. X
  170. X/*
  171. Xfloatcnt++;
  172. X*/
  173. X    res = R_makefloat();
  174. X
  175. X    R_setsign(res,R_POSITIVE);
  176. X
  177. X    resexp = 0;
  178. X    man[0] = '\0';
  179. X
  180. X    /*
  181. X    **    check for leading sign
  182. X    */
  183. X    if ('+' == *str)
  184. X    {
  185. X        /*
  186. X        **    sign should already be positive, see above in this
  187. X        **        routine, so just skip the plus sign
  188. X        */
  189. X        str++;
  190. X    }
  191. X    else
  192. X    {
  193. X        if ('-' == *str)
  194. X        {
  195. X            R_setsign(res,R_NEGATIVE);
  196. X            str++;
  197. X        }
  198. X    }
  199. X
  200. X    /*
  201. X    **    skip any leading zeros
  202. X    */
  203. X    while('0' == *str)
  204. X    {
  205. X        str++;
  206. X    }
  207. X
  208. X    /*
  209. X    **    now snarf up the digits on the left hand side
  210. X    **        of the decimal point
  211. X    */
  212. X    while(isdigit(*str))
  213. X    {
  214. X        got_a_digit = 1;
  215. X        man[length++] = *str++;
  216. X        man[length] = '\0';
  217. X        resexp++;
  218. X    }
  219. X
  220. X    /*
  221. X    **    skip the decimal point if there is one
  222. X    */
  223. X    if ('.' == *str)
  224. X        str++;
  225. X
  226. X    /*
  227. X    **    trim off any leading zeros (on the right hand side)
  228. X    **    if there were no digits in front of the decimal point.
  229. X    */
  230. X
  231. X    if (!got_a_digit)
  232. X    {
  233. X        while('0' == *str)
  234. X        {
  235. X            str++;
  236. X            resexp--;
  237. X        }
  238. X    }
  239. X
  240. X    /*
  241. X    **    now snarf up the digits on the right hand side
  242. X    */
  243. X    while(isdigit(*str))
  244. X    {
  245. X        man[length++] = *str++;
  246. X        man[length] = '\0';
  247. X    }
  248. X
  249. X    if ('e' == *str ||
  250. X            'E' == *str ||
  251. X            'd' == *str ||
  252. X            'D' == *str )
  253. X    {
  254. X        str++;
  255. X        resexp += atoi(str);
  256. X    }
  257. X
  258. X    if (allflag)
  259. X    {
  260. X        if ('+' == *str ||
  261. X            '-' == *str)
  262. X        {
  263. X            str++;
  264. X        }
  265. X        while (isdigit(*str))
  266. X        {
  267. X            str++;
  268. X        }
  269. X        if ('\0' != *str)
  270. X        {
  271. X            (void) sprintf(Z_err_buf,
  272. X                    "didn't use up all of %s in atocf",
  273. X                    beg);
  274. X            Z_fatal(Z_err_buf);
  275. X        }
  276. X    }
  277. X
  278. X    /*
  279. X    **    check for special case of all zeros in the mantissa
  280. X    */
  281. X    for (i=0;i<length;i++)
  282. X    {
  283. X        if (man[i] != '0')
  284. X        {
  285. X            /*
  286. X            **    the mantissa is non-zero, so return it unchanged
  287. X            */
  288. X            S_trimzeros(man);
  289. X            /*
  290. X            **    save a copy of the mantissa
  291. X            */
  292. X            R_setfrac(res,man);
  293. X            R_setexp(res,resexp);
  294. X            return(res);
  295. X        }
  296. X    }
  297. X
  298. X    /*
  299. X    **    the answer is 0, so . . .
  300. X    */
  301. X    R_setzero(res);
  302. X    return(res);
  303. X}
  304. X
  305. X
  306. X/*
  307. X**    add s2 to s1
  308. X*/
  309. Xstatic
  310. Xvoid
  311. X_F_stradd(s1,s2)
  312. Xchar *s1,*s2;
  313. X{
  314. X    char *end1 = s1 + (strlen(s1)-1);
  315. X    char *end2 = s2 + (strlen(s2)-1);
  316. X
  317. X    static char result[R_MANMAX];
  318. X    char *resptr = result+(R_MANMAX-1); /*point to the end of the array */
  319. X    int carry = 0;
  320. X    int tmp,val1,val2;
  321. X
  322. X    *resptr-- = '\0';
  323. X
  324. X    while ((end1 >= s1) ||  ( end2 >= s2))
  325. X    {
  326. X        if (end1 >= s1)
  327. X        {
  328. X            val1 = *end1 - '0';
  329. X            --end1;
  330. X        }
  331. X        else
  332. X        {
  333. X            val1 = 0;
  334. X        }
  335. X
  336. X        if (end2 >= s2)
  337. X        {
  338. X            val2 = *end2 - '0';
  339. X            --end2;
  340. X        }
  341. X        else
  342. X        {
  343. X            val2 = 0;
  344. X        }
  345. X
  346. X        tmp = val1 + val2 + carry;
  347. X        if (tmp > 9)
  348. X        {
  349. X            carry = 1;
  350. X            tmp -= 10;
  351. X        }
  352. X        else
  353. X        {
  354. X            carry = 0;
  355. X        }
  356. X
  357. X        *resptr-- = tmp+'0';
  358. X    }
  359. X    if (carry)
  360. X    {
  361. X        *resptr =  '1';
  362. X    }
  363. X    else
  364. X    {
  365. X        resptr++;
  366. X    }
  367. X    (void) strcpy(s1,resptr);
  368. X    return;
  369. X}
  370. X
  371. X/*
  372. X**    add zero(s) onto the end of a string
  373. X*/
  374. Xstatic void
  375. Xaddzeros(ptr,count)
  376. Xchar *ptr;
  377. Xint count;
  378. X{
  379. X    for(;count> 0;count--)
  380. X    {
  381. X        (void) strcat(ptr,"0");
  382. X    }
  383. X    return;
  384. X}
  385. X
  386. X/*
  387. X**    subtract two mantissa strings
  388. X*/
  389. XF_float
  390. XF_floatsub(p1,p2)
  391. XF_float  p1,p2;
  392. X{
  393. X    static F_float result;
  394. X    static needinit = 1;
  395. X    static char man1[R_MANMAX],man2[R_MANMAX],diff[R_MANMAX];
  396. X    int exp1,exp2;
  397. X    char *diffptr,*big,*small;
  398. X    int man_cmp_val,i,borrow;
  399. X
  400. X    if (needinit)
  401. X    {
  402. X        result = R_makefloat();
  403. X        needinit = 0;
  404. X    }
  405. X
  406. X    man1[0] = '\0';
  407. X    man2[0] = '\0';
  408. X
  409. X    exp1 = R_getexp(p1);
  410. X    exp2 = R_getexp(p2);
  411. X
  412. X    /*
  413. X    **    line up the mantissas
  414. X    */
  415. X    while (exp1 < exp2)
  416. X    {
  417. X        (void) strcat(man1,"0");
  418. X        exp1++;
  419. X    }
  420. X
  421. X    while(exp1 > exp2)
  422. X    {
  423. X        (void) strcat(man2,"0");
  424. X        exp2++;
  425. X    }
  426. X
  427. X    if (exp1 != exp2)    /* boiler plate assertion */
  428. X    {
  429. X        Z_fatal("mantissas didn't get lined up properly in floatsub");
  430. X    }
  431. X
  432. X    (void) strcat(man1,R_getfrac(p1));
  433. X    (void) strcat(man2,R_getfrac(p2));
  434. X    
  435. X    /*
  436. X    **    now that the mantissa are aligned,
  437. X    **    if the strings are the same, return 0
  438. X    */
  439. X    if((man_cmp_val = strcmp(man1,man2)) == 0)
  440. X    {
  441. X        R_setzero(result);
  442. X        return(result);
  443. X    }
  444. X
  445. X    /*
  446. X    **    pad the shorter string with 0's
  447. X    **        when this loop finishes, both mantissas should
  448. X    **        have the same length
  449. X    */
  450. X    if (strlen(man1)> strlen(man2))
  451. X    {
  452. X        addzeros(man2,strlen(man1)-strlen(man2));
  453. X    }
  454. X    else
  455. X    {
  456. X        if (strlen(man1)<strlen(man2))
  457. X        {
  458. X            addzeros(man1,strlen(man2)-strlen(man1));
  459. X        }
  460. X    }
  461. X
  462. X    if (strlen(man1) != strlen(man2))    /* pure boilerplate */
  463. X    {
  464. X        Z_fatal("lengths not equal in F_floatsub");
  465. X    }
  466. X
  467. X    if (man_cmp_val < 0)
  468. X    {
  469. X        big = man2;
  470. X        small = man1;
  471. X    }
  472. X    else
  473. X    {
  474. X        big = man1;
  475. X        small = man2;
  476. X    }
  477. X
  478. X    /*
  479. X    **    find the difference between the mantissas
  480. X    */
  481. X    for(i=(strlen(big)-1),borrow=0,diff[strlen(big)] = '\0';i>=0;i--)
  482. X    {
  483. X        char from;
  484. X        if (borrow)
  485. X        {
  486. X            if (big[i] == '0')
  487. X            {
  488. X                from = '9';
  489. X            }
  490. X            else
  491. X            {
  492. X                from = big[i]-1;
  493. X                borrow = 0;
  494. X            }
  495. X        }
  496. X        else
  497. X        {
  498. X            if(big[i]<small[i])
  499. X            {
  500. X                from = '9'+1;
  501. X                borrow = 1;
  502. X            }
  503. X            else
  504. X            {
  505. X                from = big[i];
  506. X            }
  507. X        }
  508. X        diff[i] = (from-small[i]) + '0';
  509. X    }
  510. X
  511. X    /*
  512. X    ** trim the leading zeros on the difference
  513. X    */
  514. X    diffptr = diff;
  515. X    while('0' == *diffptr)
  516. X    {
  517. X        diffptr++;
  518. X        exp1--;
  519. X    }
  520. X
  521. X    R_setexp(result,exp1); /* exponents are equal at the point */
  522. X    R_setfrac(result,diffptr);
  523. X    R_setsign(result,R_POSITIVE);
  524. X    return(result);
  525. X}
  526. X
  527. XF_floatcmp(f1,f2)
  528. XF_float f1,f2;
  529. X{
  530. X    static char man1[R_MANMAX],man2[R_MANMAX];
  531. X
  532. X    /*
  533. X    **        special case for zero
  534. X    */
  535. X    if (R_zerofloat(f1))
  536. X    {
  537. X        if (R_zerofloat(f2))
  538. X        {
  539. X            return(0);
  540. X        }
  541. X        else
  542. X        {
  543. X            return(-1);
  544. X        }
  545. X    }
  546. X    else
  547. X    {
  548. X        if (R_zerofloat(f2))
  549. X        {
  550. X            return(1);
  551. X        }
  552. X    }
  553. X
  554. X    /*
  555. X    **    to reach this point, both numbers must be non zeros
  556. X    */
  557. X    if (R_getexp(f1) < R_getexp(f2))
  558. X    {
  559. X        return(-1);
  560. X    }
  561. X
  562. X    if (R_getexp(f1) > R_getexp(f2))
  563. X    {
  564. X        return(1);
  565. X    }
  566. X
  567. X    (void) strcpy(man1,R_getfrac(f1));
  568. X    S_trimzeros(man1);
  569. X
  570. X    (void) strcpy(man2,R_getfrac(f2));
  571. X    S_trimzeros(man2);
  572. X    return(strcmp(man1,man2));
  573. X}
  574. X
  575. XF_float
  576. XF_floatmul(f1,f2)
  577. XF_float f1,f2;
  578. X{
  579. X    static char prod[R_MANMAX];
  580. X    char *end;
  581. X    int count1 = 0;
  582. X    int count2 = 0;
  583. X    int tmp,len;
  584. X    char *end1;
  585. X    char *end2;
  586. X    static char man1[R_MANMAX],man2[R_MANMAX];
  587. X    char *bigman,*smallman;
  588. X    static F_float result;
  589. X    static int needinit = 1;
  590. X
  591. X    if (needinit)
  592. X    {
  593. X        result = R_makefloat();
  594. X        needinit = 0;
  595. X    }
  596. X    /*
  597. X    **    special case for a zero result
  598. X    */
  599. X    if (R_zerofloat(f1) || R_zerofloat(f2))
  600. X    {
  601. X        R_setzero(result);
  602. X        return(result);
  603. X    }
  604. X
  605. X    (void) strcpy(man1,R_getfrac(f1));
  606. X    (void) strcpy(man2,R_getfrac(f2));
  607. X
  608. X    end1 = _F_GETEND(man1);
  609. X    end2 = _F_GETEND(man2);
  610. X
  611. X    /*
  612. X    **    decide which number will cause multiplication loop to go
  613. X    **    around the least
  614. X    */
  615. X    while(end1 >= man1)
  616. X    {
  617. X        count1 += *end1 - '0';
  618. X        end1--;
  619. X    }
  620. X
  621. X    while(end2 >= man2)
  622. X    {
  623. X        count2 += *end2 - '0';
  624. X        end2--;
  625. X    }
  626. X
  627. X
  628. X    if (count1 > count2)
  629. X    {
  630. X        bigman = man1;
  631. X        smallman = man2;
  632. X    }
  633. X    else
  634. X    {
  635. X        bigman = man2;
  636. X        smallman = man1;
  637. X    }
  638. X    S_trimzeros(bigman);
  639. X    S_trimzeros(smallman);
  640. X    len = strlen(bigman) +  strlen(smallman);
  641. X
  642. X    end = _F_GETEND(smallman);
  643. X    (void) strcpy(prod,"0");
  644. X
  645. X    /*
  646. X    **    multiplication by repeated addition
  647. X    */
  648. X    while(end >= smallman)
  649. X    {
  650. X        for(tmp = 0;tmp<*end-'0';tmp++)
  651. X        {
  652. X            _F_stradd(prod,bigman);
  653. X        }
  654. X        addzeros(bigman,1);
  655. X        end--;
  656. X    }
  657. X
  658. X    R_setfrac(result,prod);
  659. X    R_setexp(result,(((R_getexp(f1) + R_getexp(f2)) - len)+ strlen(prod)));
  660. X
  661. X    if (R_getsign(f1) == R_getsign(f2))
  662. X    {
  663. X        R_setsign(result,R_POSITIVE);
  664. X    }
  665. X    else
  666. X    {
  667. X        R_setsign(result,R_NEGATIVE);
  668. X    }
  669. X    return(result);
  670. X}
  671. X
  672. X_F_xor(x,y)
  673. X{
  674. X    return(((x) && !(y)) || (!(x) && (y)));
  675. X}
  676. X#define    _F_SAMESIGN(x,y)    _F_xor((x<0),(y<0))
  677. X#define _F_ABSADD(x,y)        (Z_ABS(x) + Z_ABS(y))
  678. X
  679. X_F_ABSDIFF(x,y)
  680. X{
  681. X    if (Z_ABS(x) < Z_ABS(y))
  682. X    {
  683. X        return(Z_ABS(y) - Z_ABS(x));
  684. X    }
  685. X    else
  686. X    {
  687. X        return(Z_ABS(x) - Z_ABS(y));
  688. X    }
  689. X}
  690. X/*
  691. X**    add two floats without regard to sign
  692. X*/
  693. XF_float
  694. XF_floatmagadd(p1,p2)
  695. XF_float p1,p2;
  696. X{
  697. X    static F_float result;
  698. X    static int needinit = 1;
  699. X
  700. X    static char  man1[R_MANMAX],man2[R_MANMAX];
  701. X
  702. X    int digits;    /* count of the number of digits needed to represent the
  703. X                result */
  704. X    int resexp;    /* exponent of the result */
  705. X    int len;    /* length of the elements before adding */
  706. X    char *diffptr;
  707. X
  708. X    if (needinit)
  709. X    {
  710. X        result = R_makefloat();
  711. X        needinit = 0;
  712. X    }
  713. X    (void) strcpy(man1,"");
  714. X    (void) strcpy(man2,"");
  715. X
  716. X    /*
  717. X    **    find the difference in the exponents number of digits
  718. X    */
  719. X    if( _F_SAMESIGN(R_getexp(p1),R_getexp(p2)))
  720. X    {
  721. X        digits =  _F_ABSDIFF(R_getexp(p1),R_getexp(p2));
  722. X    }
  723. X    else
  724. X    {
  725. X        digits = _F_ABSADD(R_getexp(p1),R_getexp(p2));
  726. X    }
  727. X
  728. X    /*
  729. X    **    make sure that there is room to store the result
  730. X    */
  731. X    if (digits>0)
  732. X    { 
  733. X        if (R_getexp(p1) < R_getexp(p2))
  734. X        {
  735. X            /*
  736. X            **    leave room for terminator
  737. X            */
  738. X            if (digits+strlen(R_getfrac(p1)) > (R_MANMAX-1))
  739. X            {
  740. X                (void) sprintf(Z_err_buf,
  741. X                   "numbers differ by too much in magnitude");
  742. X                Z_fatal(Z_err_buf);
  743. X            }
  744. X        }
  745. X        else
  746. X        {
  747. X            /*
  748. X            **    leave room for terminator
  749. X            */
  750. X            if (digits+strlen(R_getfrac(p2)) > (R_MANMAX-1))
  751. X            {
  752. X                (void) sprintf(Z_err_buf,
  753. X                   "numbers differ by too much in magnitude");
  754. X                Z_fatal(Z_err_buf);
  755. X            }
  756. X        }
  757. X    }
  758. X    else
  759. X    {
  760. X        /*
  761. X        **    leave room for terminator and possible carry
  762. X        */
  763. X        if (Z_MAX(strlen(R_getfrac(p1)),
  764. X            strlen(R_getfrac(p2))) > (R_MANMAX-2))
  765. X        {                        
  766. X            (void) sprintf(Z_err_buf,
  767. X               "numbers differ by too much in magnitude");
  768. X            Z_fatal(Z_err_buf);
  769. X        }
  770. X    }
  771. X
  772. X    /*
  773. X    **    pad zeroes on the front of the smaller number
  774. X    */
  775. X    if (R_getexp(p1) < R_getexp(p2))
  776. X    {
  777. X
  778. X        addzeros(man1,digits);
  779. X        resexp = R_getexp(p2);
  780. X    }
  781. X    else
  782. X    {
  783. X        addzeros(man2,digits);
  784. X        resexp = R_getexp(p1);
  785. X    }
  786. X    (void) strcat(man1,R_getfrac(p1));
  787. X    (void) strcat(man2,R_getfrac(p2));
  788. X
  789. X    len = Z_MAX(strlen(man1),strlen(man2));
  790. X
  791. X    /*
  792. X    **    add the two values
  793. X    */
  794. X    _F_stradd(man1,man2);
  795. X
  796. X    /*
  797. X    **    adjust the exponent to account for a
  798. X    **        possible carry
  799. X    */
  800. X    resexp += strlen(man1) - len;
  801. X
  802. X
  803. X    /*
  804. X    ** trim the leading zeros on the sum
  805. X    */
  806. X    diffptr = man1;
  807. X    while('0' == *diffptr)
  808. X    {
  809. X        diffptr++;
  810. X        resexp--;
  811. X    }
  812. X
  813. X    R_setfrac(result,diffptr);
  814. X    R_setexp(result,resexp);
  815. X    R_setsign(result,R_POSITIVE);
  816. X
  817. X    return(result);
  818. X}
  819. X
  820. X/*
  821. X**    useful debugging routine. we don't call it in the release,
  822. X**    so it is commented out, but we'll leave it for future use
  823. X*/
  824. X
  825. X/*
  826. XF_printfloat(fl)
  827. XF_float fl;
  828. X{
  829. X    (void) printf("fraction = :%s: exp = %d sign = %c\n",
  830. X            R_getfrac(fl),
  831. X            R_getexp(fl),
  832. X            ((R_getsign(fl) == R_POSITIVE) ? '+': '-'));
  833. X
  834. X}
  835. X*/
  836. END_OF_FILE
  837. if test 13078 -ne `wc -c <'float.c'`; then
  838.     echo shar: \"'float.c'\" unpacked with wrong size!
  839. fi
  840. # end of 'float.c'
  841. fi
  842. if test -f 'parse.c' -a "${1}" != "-c" ; then 
  843.   echo shar: Will not clobber existing file \"'parse.c'\"
  844. else
  845. echo shar: Extracting \"'parse.c'\" \(16604 characters\)
  846. sed "s/^X//" >'parse.c' <<'END_OF_FILE'
  847. X/*                        Copyright (c) 1988 Bellcore
  848. X**                            All Rights Reserved
  849. X**       Permission is granted to copy or use this program, EXCEPT that it
  850. X**       may not be sold for profit, the copyright notice must be reproduced
  851. X**       on copies, and credit should be given to Bellcore where it is due.
  852. X**       BELLCORE MAKES NO WARRANTY AND ACCEPTS NO LIABILITY FOR THIS PROGRAM.
  853. X*/
  854. X
  855. X
  856. X#ifndef lint
  857. Xstatic char rcsid[]= "$Header: parse.c,v 1.1 88/09/15 11:33:57 daniel Rel $";
  858. X#endif
  859. X
  860. X#include "misc.h"
  861. X#include "flagdefs.h"
  862. X#include "float.h"
  863. X#include "tol.h"
  864. X#include "token.h"
  865. X#include "line.h"
  866. X#include "command.h"
  867. X#include "comment.h"
  868. X#include "parse.h"
  869. X
  870. X
  871. X#include <ctype.h>
  872. X
  873. X#define _P_PARSE_CHATTER    1000
  874. X
  875. X
  876. Xstatic    int _P_realline;    /* loop counter */
  877. Xstatic  int _P_fnumb;
  878. X
  879. Xstatic  char *_P_nextchr;    /* pointer to the next character to parse */
  880. Xstatic    char *_P_firstchr;        /* pointer to the beginning of the line being parsed */
  881. Xstatic    int _P_next_tol;        /* number of floats seen on this line */
  882. Xstatic    int _P_stringsize;        /* count of number of characters that are being
  883. X                    read into a comment or literal */
  884. Xstatic int _P_has_content;    /* flag to indicate if the line being
  885. X                    parsed has any tokens on it */
  886. Xstatic int _P_start;        /* first line to parse */
  887. Xstatic int _P_lcount;        /* number of lines to parse */
  888. X
  889. Xstatic int _P_flags;        /* location for global flags */
  890. X
  891. X/*
  892. X**    by default, "words" can be made up of numbers and letters
  893. X**    the following code allows for extending the alphabet that can
  894. X**    be used in words. this is useful for handling languages such
  895. X**    as C where the underscore character is an allowable character
  896. X**    in an identifier.  If a character (such as underscore) is NOT added
  897. X**    to the alphabet, the identifier will be broken into 2 or more "words"
  898. X**    by the parser.  as such the two sequences
  899. X**            one_two
  900. X**        and
  901. X**            one _ two
  902. X**    would look identical to spiff.
  903. X*/
  904. X#define _P_ALPHALEN 256
  905. Xstatic char _P_alpha[_P_ALPHALEN];
  906. X
  907. Xstatic void
  908. X_P_alpha_clear()
  909. X{
  910. X    *_P_alpha = '\0';
  911. X}
  912. X
  913. Xstatic
  914. X_P_in_alpha(chr)
  915. Xchar chr;
  916. X{
  917. X#ifndef ATT
  918. X    extern int index();
  919. X#endif
  920. X    /*
  921. X    **    special case when string terminator
  922. X    **    is handed to us
  923. X    */
  924. X    if ('\0' == chr)
  925. X        return(0);
  926. X
  927. X#ifdef ATT
  928. X    return((int) strchr(_P_alpha,chr));
  929. X#else
  930. X    return((int) index(_P_alpha,chr));
  931. X#endif
  932. X}
  933. X
  934. Xvoid
  935. XP_addalpha(ptr)
  936. Xchar *ptr;
  937. X{
  938. X    char buf[Z_LINELEN];
  939. X
  940. X    S_wordcpy(buf,ptr);        /* copy up to (but not including)
  941. X                        the first whitespace char */
  942. X
  943. X    if ((strlen(_P_alpha) + strlen(buf)) >= _P_ALPHALEN)
  944. X    {
  945. X        Z_fatal("too many characters added to extended alphabet");
  946. X    }
  947. X    (void) strcat(_P_alpha,buf);
  948. X}
  949. X
  950. X/*
  951. X**    put parser in a default state
  952. X*/
  953. X
  954. Xstatic char _P_dummyline[2];    /* a place to aim wild pointers */
  955. Xstatic void
  956. X_P_initparser()
  957. X{
  958. X    _P_dummyline[0] = '\0';
  959. X
  960. X    /*
  961. X    **    now reset all the state of each module
  962. X    */
  963. X    C_clear_cmd();        /* disable embedded command key word */ 
  964. X    T_clear_tols();
  965. X    W_clearcoms();
  966. X    W_clearlits();
  967. X    _P_alpha_clear();    /* disable extended alphabet */
  968. X
  969. X    /*
  970. X    **    and set state as defined by execute-time commands.
  971. X    */
  972. X    C_docmds();
  973. X    return;
  974. X}
  975. X
  976. X
  977. Xstatic
  978. X_P_needmore()
  979. X{
  980. X    return(*_P_nextchr == '\0');
  981. X}
  982. X
  983. Xstatic
  984. X_P_nextline()
  985. X{
  986. X    /*
  987. X    **    if the line that we just finished had
  988. X    **        some content,  increment the count
  989. X    */
  990. X    if (_P_has_content)
  991. X    {
  992. X        L_incclmax(_P_fnumb);
  993. X        /*
  994. X        **    if the previous line had a token
  995. X        **        increment the line
  996. X        */
  997. X        if (L_getcount(_P_fnumb,L_gettlmax(_P_fnumb)))
  998. X        {
  999. X            L_inctlmax(_P_fnumb);
  1000. X            L_setcount(_P_fnumb,L_gettlmax(_P_fnumb),0);
  1001. X        }
  1002. X        _P_has_content = 0;
  1003. X    }
  1004. X
  1005. X    /*
  1006. X    **    reset the number of floats seen on the line
  1007. X    */
  1008. X    _P_next_tol = 0;
  1009. X
  1010. X    /*
  1011. X    **    get another line if there is one available
  1012. X    */
  1013. X    _P_realline++;
  1014. X    if (_P_realline >= _P_start+_P_lcount)
  1015. X    {
  1016. X        return(1);
  1017. X    }
  1018. X
  1019. X    _P_firstchr = _P_nextchr = L_getrline(_P_fnumb,_P_realline);
  1020. X    /*
  1021. X    **    and look for a command
  1022. X    */
  1023. X    if (C_is_cmd(_P_firstchr))
  1024. X    {
  1025. X        _P_nextchr = _P_dummyline;
  1026. X        _P_has_content = 0;
  1027. X    }
  1028. X    else
  1029. X    {
  1030. X        /*
  1031. X        **    we have a real line, so set up the index
  1032. X        */
  1033. X        L_setclindex(_P_fnumb,L_getclmax(_P_fnumb),_P_realline);
  1034. X        _P_has_content = 1;
  1035. X    }
  1036. X    return(0);
  1037. X}
  1038. X
  1039. X/*
  1040. X**    the following three routines (_P_litsnarf, _P_bolsnarf, and _P_comsnarf
  1041. X**    all do roughly the same thing. they scan ahead and collect the
  1042. X**    specified string, move _P_nextchr to the end of the
  1043. X**    comment or literal and return 1 if we run off the end of file,
  1044. X**    0 otherwise.  it would have been nice to have 1 routine handle
  1045. X**    all three task (there is much common code), however there were
  1046. X**    so enough differences, (for instance, only comments check for nesting,
  1047. X**    only literals need to set _P_stringsize, etc)
  1048. X**    that I decided to split them up.
  1049. X*/
  1050. Xstatic int
  1051. X_P_litsnarf(litptr)
  1052. XW_lit litptr; 
  1053. X{
  1054. X    _P_stringsize = 0;
  1055. X    /*
  1056. X    **    skip the start of literal string
  1057. X    */
  1058. X    _P_nextchr += strlen(W_litbegin(litptr));
  1059. X    _P_stringsize += strlen(W_litbegin(litptr));
  1060. X    /*
  1061. X    **    is there a separate end string?
  1062. X    **        if not, then we're done
  1063. X    */
  1064. X    if ('\0' == *(W_litend(litptr)))
  1065. X    {
  1066. X        return(0);
  1067. X    }
  1068. X    /*
  1069. X    **    loop once for each character in the literal
  1070. X    */
  1071. X    while(1)
  1072. X    {
  1073. X        /*
  1074. X        **    if we are out of characters, move on to next line
  1075. X        */
  1076. X        if (_P_needmore())
  1077. X        {
  1078. X            if (_P_nextline())
  1079. X            {
  1080. X                return(1);
  1081. X            }
  1082. X            if (!_P_has_content)
  1083. X            {
  1084. X                /*
  1085. X                **    since we've just gotten a command
  1086. X                **        check to see if this literal
  1087. X                **        is still legit ...
  1088. X                **        could have just been reset
  1089. X                **        by the command
  1090. X                */
  1091. X                if (!W_is_lit(litptr))
  1092. X                {
  1093. X                    return(0);
  1094. X                }
  1095. X            }
  1096. X        } /* if _P_needmore */
  1097. X
  1098. X        /*
  1099. X        **    see if we have an escaped end of literal string
  1100. X        */
  1101. X        if (('\0' != *(W_litescape(litptr))) && /* escape string exists */
  1102. X          !S_wordcmp(_P_nextchr,
  1103. X               W_litescape(litptr)) &&     /* and escape matches */
  1104. X          !S_wordcmp(_P_nextchr+strlen(W_litescape(litptr)),
  1105. X               W_litend(litptr)))         /* and endstring matches */
  1106. X        {
  1107. X            _P_nextchr += strlen(W_litescape(litptr))
  1108. X                    + strlen(W_litend(litptr));
  1109. X            _P_stringsize += strlen(W_litescape(litptr))
  1110. X                    + strlen(W_litend(litptr));
  1111. X            continue;
  1112. X        }
  1113. X
  1114. X        /*
  1115. X        **    see if we have an end of literal string
  1116. X        */
  1117. X        if (!S_wordcmp(_P_nextchr,W_litend(litptr))) /* escape matches */
  1118. X        {
  1119. X            _P_nextchr += strlen(W_litend(litptr));
  1120. X            _P_stringsize += strlen(W_litend(litptr));
  1121. X            return(0);
  1122. X        }
  1123. X        /*
  1124. X        **    this must be yet another character in the literal, so
  1125. X        **    just snarf it up
  1126. X        */
  1127. X        _P_nextchr++;
  1128. X        _P_stringsize++;
  1129. X    }    /* while loop once for each character */
  1130. X
  1131. X#ifndef lint
  1132. X    Z_fatal("shouldn't execute this line at the end of _P_litsnarf");
  1133. X#endif
  1134. X} /* _P_litsnarf */
  1135. X
  1136. Xstatic int
  1137. X_P_bolsnarf(bolptr)
  1138. XW_bol bolptr; 
  1139. X{
  1140. X    /*
  1141. X    **    skip the start of comment string
  1142. X    */
  1143. X    _P_nextchr += strlen(W_bolbegin(bolptr));
  1144. X    /*
  1145. X    **    is there a separate end string
  1146. X    **        if not, then we're done
  1147. X    */
  1148. X    if ('\0' == *(W_bolend(bolptr)))
  1149. X    {
  1150. X        return(0);
  1151. X    }
  1152. X    /*
  1153. X    **    loop once for each character in the comment
  1154. X    */
  1155. X    while(1)
  1156. X    {
  1157. X        /*
  1158. X        **    if we are out of characters,move on to next line
  1159. X        */
  1160. X        if (_P_needmore())
  1161. X        {
  1162. X            if (_P_nextline())
  1163. X            {
  1164. X                return(1);
  1165. X            }
  1166. X            if (!_P_has_content)
  1167. X            {
  1168. X                /*
  1169. X                **    since we've just gotten a command
  1170. X                **        check to see if this comment
  1171. X                **        is still legit ... comments
  1172. X                **        could have just been reset
  1173. X                **        by the command
  1174. X                */
  1175. X                if (!W_is_bol(bolptr))
  1176. X                {
  1177. X                    return(0);
  1178. X                }
  1179. X            }
  1180. X        } /* if at end of line */
  1181. X
  1182. X        /*
  1183. X        **    see if we have an escaped end of comment string
  1184. X        */
  1185. X        if ('\0' != *(W_bolescape(bolptr)) && /* escape string exists */
  1186. X          !S_wordcmp(_P_nextchr,
  1187. X               W_bolescape(bolptr)) &&     /* and escape matches */
  1188. X          !S_wordcmp(_P_nextchr+strlen(W_bolescape(bolptr)),
  1189. X               W_bolend(bolptr)))     /* and end string matches */
  1190. X        {
  1191. X            _P_nextchr += strlen(W_bolescape(bolptr))
  1192. X                    + strlen(W_bolend(bolptr));
  1193. X            continue;
  1194. X        }
  1195. X
  1196. X        /*
  1197. X        **    see if we have an end of comment string
  1198. X        */
  1199. X        if (!S_wordcmp(_P_nextchr,W_bolend(bolptr)))
  1200. X        {
  1201. X            _P_nextchr += strlen(W_bolend(bolptr));
  1202. X            return(0);
  1203. X        }
  1204. X        /*
  1205. X        **    this must be yet another character in the comment, so
  1206. X        **    just snarf it up
  1207. X        */
  1208. X        _P_nextchr++;
  1209. X    }    /* while loop once for each character */
  1210. X
  1211. X#ifndef lint
  1212. X    Z_fatal("shouldn't execute this line in at end of _P_bolsnarf");
  1213. X#endif
  1214. X} /* _P_bolsnarf */
  1215. X
  1216. X/*
  1217. X**    pass over a comment -- look for nexting
  1218. X*/
  1219. Xstatic
  1220. X_P_comsnarf(comptr)
  1221. XW_com comptr; 
  1222. X{
  1223. X    int depth = 1; /* nesting depth */
  1224. X    /*
  1225. X    **    skip the start of comment string
  1226. X    */
  1227. X    _P_nextchr += strlen(W_combegin(comptr));
  1228. X
  1229. X    /*
  1230. X    **    is there a separate end string
  1231. X    **        if not, then we're done
  1232. X    */
  1233. X    if ('\0' == *(W_comend(comptr)))
  1234. X    {
  1235. X        return(0);
  1236. X    }
  1237. X    /*
  1238. X    **    loop once for each character in the comment
  1239. X    */
  1240. X    while(1)
  1241. X    {
  1242. X        /*
  1243. X        **    if we are out of characters, move on to next line
  1244. X        */
  1245. X        if (_P_needmore())
  1246. X        {
  1247. X            if (_P_nextline())
  1248. X            {
  1249. X                return(1);
  1250. X            }
  1251. X            if (!_P_has_content)
  1252. X            {
  1253. X                /*
  1254. X                **    since we've just gotten a command
  1255. X                **        check to see if this comment
  1256. X                **        is still legit ... comments
  1257. X                **        could have just been reset
  1258. X                **        by the command
  1259. X                */
  1260. X                if (!W_is_com(comptr))
  1261. X                {
  1262. X                    return(0);
  1263. X                }
  1264. X            }
  1265. X        } /* if at end of line */
  1266. X
  1267. X        /*
  1268. X        **    see if we have an escaped end of comment string
  1269. X        */
  1270. X        if ('\0' != *(W_comescape(comptr)) &&  /* escape string exists */
  1271. X          !S_wordcmp(_P_nextchr,
  1272. X               W_comescape(comptr)) &&    /* and escape matches */
  1273. X          !S_wordcmp(_P_nextchr+strlen(W_comescape(comptr)),
  1274. X               W_comend(comptr)))    /* and end string matches */
  1275. X        {
  1276. X            /*
  1277. X            ** skip over the escape sequence and the end sequence
  1278. X            */
  1279. X            _P_nextchr += strlen(W_comescape(comptr))
  1280. X                    + strlen(W_comend(comptr));
  1281. X            continue;
  1282. X        }
  1283. X
  1284. X        /*
  1285. X        **    see if we have an end of comment string
  1286. X        */
  1287. X        if (!S_wordcmp(_P_nextchr,W_comend(comptr))) /* end  matches */
  1288. X        {
  1289. X            /*
  1290. X            **    skip over the end sequence
  1291. X            */
  1292. X            _P_nextchr += strlen(W_comend(comptr));
  1293. X            if (W_is_nesting(comptr))
  1294. X            {
  1295. X                depth--;
  1296. X                if (0 == depth)
  1297. X                    return(0);
  1298. X            }
  1299. X            else
  1300. X            {
  1301. X                return(0);
  1302. X            }
  1303. X            continue;
  1304. X        }
  1305. X        /*
  1306. X        **    see if we have another beginning of comment string
  1307. X        */
  1308. X        if (W_is_nesting(comptr) &&
  1309. X            !S_wordcmp(_P_nextchr,W_comend(comptr))) /* end matches */
  1310. X        {
  1311. X            _P_nextchr += strlen(W_comend(comptr));
  1312. X            depth++;
  1313. X            continue;
  1314. X        }
  1315. X        /*
  1316. X        **    this must be yet another character in the comment, so
  1317. X        **    just snarf it up
  1318. X        */
  1319. X        _P_nextchr++;
  1320. X    }    /* while loop once for each character */
  1321. X
  1322. X#ifndef lint
  1323. X        Z_fatal("should not execute this line in _P_comsnarf\n");
  1324. X#endif
  1325. X
  1326. X} /* _P_comsnarf */
  1327. X
  1328. X
  1329. X/*
  1330. X**    parse a file
  1331. X*/
  1332. Xstatic void
  1333. X_P_do_parse()
  1334. X{
  1335. X
  1336. X    char *ptr;        /* scratch space */
  1337. X    int tmp;
  1338. X    int ret_code;
  1339. X
  1340. X    K_token newtoken;
  1341. X    W_bol bolptr;
  1342. X    W_com comptr;
  1343. X    W_lit litptr;
  1344. X
  1345. X    int startline, endline, startpos;
  1346. X
  1347. X    /*
  1348. X    **    main parsing loop
  1349. X    */
  1350. X    while (1)
  1351. X    {
  1352. X        /*
  1353. X        **    get more text if necessary
  1354. X        */
  1355. X        if (_P_needmore())
  1356. X        {
  1357. X            if (_P_nextline())
  1358. X            {
  1359. X                return;
  1360. X            }
  1361. X
  1362. X            /*
  1363. X            **    if the line contains nothing of interest,
  1364. X            **        try again
  1365. X            */
  1366. X            if (!_P_has_content)
  1367. X            {
  1368. X                continue;
  1369. X            }
  1370. X
  1371. X            /*
  1372. X            **    check to see if this line starts a comment
  1373. X            */
  1374. X            if ((bolptr = W_isbol(_P_firstchr)) != W_BOLNULL)
  1375. X            {
  1376. X                if (_P_bolsnarf(bolptr))
  1377. X                {
  1378. X                    return;
  1379. X                }
  1380. X                continue;
  1381. X            }
  1382. X        } /* if _P_needmore */
  1383. X
  1384. X        /*
  1385. X        **    skip whitespace
  1386. X        */
  1387. X        if (!(U_INCLUDE_WS & _P_flags) && isspace(*_P_nextchr))
  1388. X        {
  1389. X            _P_nextchr++;
  1390. X            continue;
  1391. X        }
  1392. X
  1393. X        /*
  1394. X        **    check to see if this character starts a comment
  1395. X        */
  1396. X        if ((comptr = W_iscom(_P_nextchr)) != W_COMNULL)
  1397. X        {
  1398. X            if (_P_comsnarf(comptr))
  1399. X            {
  1400. X                return;
  1401. X            }
  1402. X            continue;
  1403. X        }
  1404. X
  1405. X        /*
  1406. X        **    if there aren't any tokens on this line already
  1407. X        **    set up the index from the token line to the content line
  1408. X        */
  1409. X        if (!L_getcount(_P_fnumb,L_gettlmax(_P_fnumb)))
  1410. X        {
  1411. X            L_settlindex(_P_fnumb,
  1412. X                    L_gettlmax(_P_fnumb),
  1413. X                    L_getclmax(_P_fnumb));
  1414. X            /*
  1415. X            **    and the pointer from the token line to the 
  1416. X            **     first  token on the line
  1417. X            */
  1418. X            L_setindex(_P_fnumb,
  1419. X                    L_gettlmax(_P_fnumb),
  1420. X                    K_gettmax(_P_fnumb));
  1421. X        }
  1422. X
  1423. X        startline =  L_tl2cl(_P_fnumb,L_gettlmax(_P_fnumb));
  1424. X        startpos = _P_nextchr-_P_firstchr;
  1425. X
  1426. X        newtoken = K_maketoken();
  1427. X        K_setline(newtoken,L_gettlmax(_P_fnumb));
  1428. X        K_setpos(newtoken,startpos);
  1429. X
  1430. X        ret_code = 0;
  1431. X        /*
  1432. X        **    check to see if this character starts a
  1433. X        **        delimited literal string
  1434. X        */
  1435. X        if ((litptr = W_islit(_P_nextchr)) != W_LITNULL)
  1436. X        {
  1437. X            ret_code = _P_litsnarf(litptr);
  1438. X            K_settype(newtoken,K_LIT);
  1439. X            S_allocstr(&ptr,_P_stringsize);
  1440. X            /*
  1441. X            **    fixed nasty memory bug here by adding else
  1442. X            **    old code copied entire line even if literal
  1443. X            **    ended before the end of line
  1444. X            **        should check into getting strcpy loaded
  1445. X            **        locally
  1446. X            */
  1447. X            endline = L_getclmax(_P_fnumb);
  1448. X            if (endline > startline)
  1449. X            {
  1450. X                /*
  1451. X                **    copy in the first line of the literal
  1452. X                */
  1453. X                (void) strcpy(ptr,
  1454. X                          L_getcline(_P_fnumb,startline)
  1455. X                            +startpos);
  1456. X                /*
  1457. X                **    now copy all the lines between
  1458. X                **        the first and last
  1459. X                */
  1460. X                for (tmp=startline+1;tmp<endline;tmp++)
  1461. X                {
  1462. X                    (void) strcat(ptr,
  1463. X                              L_getcline(_P_fnumb,tmp));
  1464. X                }
  1465. X                /*
  1466. X                **    and now copy in the last line
  1467. X                */
  1468. X                (void) strncat(ptr,
  1469. X                           L_getcline(_P_fnumb,endline),
  1470. X                           _P_stringsize-strlen(ptr));
  1471. X            }
  1472. X            else
  1473. X            {
  1474. X                (void) strncpy(ptr,
  1475. X                           L_getcline(_P_fnumb,startline)
  1476. X                                +startpos,
  1477. X                          _P_stringsize);
  1478. X                /*
  1479. X                **    terminate the string you just copied
  1480. X                */
  1481. X                ptr[_P_stringsize] = '\0';
  1482. X            }
  1483. X            K_settext(newtoken,ptr);
  1484. X        } /* if is_lit */
  1485. X
  1486. X        /*
  1487. X        **    see if this is a floating point number
  1488. X        */
  1489. X        else if (tmp = F_isfloat(_P_nextchr,
  1490. X                       _P_flags & U_NEED_DECIMAL,
  1491. X                       _P_flags & U_INC_SIGN))
  1492. X        {
  1493. X            K_saventext(newtoken,_P_nextchr,tmp);
  1494. X            K_settype(newtoken,K_FLO_NUM);
  1495. X            if (!(_P_flags & U_BYTE_COMPARE))
  1496. X            {
  1497. X                K_setfloat(newtoken,
  1498. X                       F_atof(K_gettext(newtoken),
  1499. X                       USE_ALL));
  1500. X
  1501. X                /*
  1502. X                **    assign the curent tolerance
  1503. X                */
  1504. X                K_settol(newtoken,T_gettol(_P_next_tol));
  1505. X            }
  1506. X
  1507. X            /*
  1508. X            **    use next tolerance in the
  1509. X            **        specification if there is one
  1510. X            */
  1511. X            if (T_moretols(_P_next_tol))
  1512. X            {
  1513. X                _P_next_tol++;
  1514. X            }
  1515. X            /*
  1516. X            **    and move pointer past the float
  1517. X            */
  1518. X            _P_nextchr += tmp;
  1519. X        }
  1520. X
  1521. X        /*
  1522. X        **    is this a fixed point number
  1523. X        */
  1524. X        else if (isdigit(*_P_nextchr))
  1525. X        {
  1526. X            for(ptr=_P_nextchr; isdigit(*ptr); ptr++)
  1527. X            {
  1528. X            }
  1529. X            K_saventext(newtoken,_P_nextchr,ptr-_P_nextchr);
  1530. X            K_settype(newtoken,K_LIT);
  1531. X            _P_nextchr = ptr;
  1532. X        }
  1533. X
  1534. X        /*
  1535. X        **    try an alpha-numeric word
  1536. X        */
  1537. X        else if (isalpha(*_P_nextchr) || _P_in_alpha(*_P_nextchr))
  1538. X        {
  1539. X            /*
  1540. X            **    it's a multi character word
  1541. X            */
  1542. X            for(ptr = _P_nextchr;
  1543. X                isalpha(*ptr)
  1544. X                || isdigit(*ptr)
  1545. X                || _P_in_alpha(*ptr);
  1546. X                ptr++)
  1547. X            {
  1548. X            }
  1549. X            K_saventext(newtoken,_P_nextchr,ptr-_P_nextchr);
  1550. X            K_settype(newtoken,K_LIT);
  1551. X            _P_nextchr = ptr;
  1552. X        }
  1553. X        else
  1554. X        {
  1555. X            /*
  1556. X            **    otherwise, treat the char itself as a token
  1557. X            */
  1558. X            K_saventext(newtoken,_P_nextchr,1);
  1559. X            K_settype(newtoken,K_LIT);
  1560. X            _P_nextchr++;
  1561. X        }
  1562. X
  1563. X        K_settoken(_P_fnumb,K_gettmax(_P_fnumb),newtoken);
  1564. X        L_inccount(_P_fnumb,L_gettlmax(_P_fnumb));
  1565. X        /*
  1566. X        **    if we are out of space, complain and quit
  1567. X        */
  1568. X        if (K_inctmax(_P_fnumb))
  1569. X        {
  1570. X            (void) sprintf(Z_err_buf,
  1571. X     "warning -- to many tokens in file only first %d tokens will be used.\n",
  1572. X                       K_MAXTOKENS);
  1573. X            Z_complain(Z_err_buf);
  1574. X            return;
  1575. X        }
  1576. X#ifndef NOCHATTER
  1577. X        if (0 == (K_gettmax(_P_fnumb) % _P_PARSE_CHATTER))
  1578. X        {
  1579. X            int max = K_gettmax(_P_fnumb);
  1580. X            (void) sprintf(Z_err_buf,
  1581. X                "scanned %d words from file #%d\n",
  1582. X                    max,_P_fnumb+1);
  1583. X            Z_chatter(Z_err_buf);
  1584. X        }
  1585. X#endif
  1586. X
  1587. X        /*
  1588. X        **    are we done?
  1589. X        */
  1590. X        if(ret_code)
  1591. X        {
  1592. X            return;
  1593. X        }
  1594. X    }   /* loop once per object on a line */
  1595. X
  1596. X#ifndef lint 
  1597. X    Z_fatal("this line should never execute");
  1598. X#endif
  1599. X}
  1600. X
  1601. Xvoid
  1602. XP_file_parse(num,strt,lcnt,flags)
  1603. Xint num;    /* file number */
  1604. Xint strt;    /* first line to parse expressed in real line numbers */
  1605. Xint lcnt;    /* max number of lines to parse */
  1606. Xint flags;    /* flags for controlling the parse mode */
  1607. X{
  1608. X    /*
  1609. X    **    set module-wide state variables
  1610. X    */
  1611. X    _P_fnumb = num;        
  1612. X    _P_start = strt;    
  1613. X    _P_lcount = lcnt;
  1614. X    _P_flags = flags;
  1615. X
  1616. X    _P_initparser();
  1617. X
  1618. X    _P_nextchr = _P_dummyline;
  1619. X
  1620. X    _P_has_content = 0;
  1621. X    _P_next_tol = 0;
  1622. X    L_setcount(_P_fnumb,L_gettlmax(_P_fnumb),0);
  1623. X    /*
  1624. X    **    start everything back one line (it will be incremented
  1625. X    **        just before the first line is accessed
  1626. X    */
  1627. X    _P_realline = _P_start-1;
  1628. X
  1629. X    _P_do_parse();
  1630. X
  1631. X    /*
  1632. X    **    if the last line had content, increment the count
  1633. X    */
  1634. X    if (_P_has_content)
  1635. X    {
  1636. X/*
  1637. X**    this code will get executed if we stopped parsing in the middle
  1638. X**    of a line.  i haven't looked at this case carefully.
  1639. X**    so, there is a good chance that it is buggy.
  1640. X*/
  1641. X(void) sprintf(Z_err_buf,"parser got confused at end of file\n");
  1642. XZ_complain(Z_err_buf);
  1643. X        L_incclmax(_P_fnumb);
  1644. X        if (L_getcount(_P_fnumb,L_gettlmax(_P_fnumb)))
  1645. X            L_inctlmax(_P_fnumb);
  1646. X    }
  1647. X    return;
  1648. X}
  1649. END_OF_FILE
  1650. if test 16604 -ne `wc -c <'parse.c'`; then
  1651.     echo shar: \"'parse.c'\" unpacked with wrong size!
  1652. fi
  1653. # end of 'parse.c'
  1654. fi
  1655. if test -f 'spiff.1' -a "${1}" != "-c" ; then 
  1656.   echo shar: Will not clobber existing file \"'spiff.1'\"
  1657. else
  1658. echo shar: Extracting \"'spiff.1'\" \(14738 characters\)
  1659. sed "s/^X//" >'spiff.1' <<'END_OF_FILE'
  1660. X.ll 6i
  1661. X.pl 10.5i
  1662. X.po 1.25i
  1663. X.\"    @(#)spiff.1    1.0 (Bellcore) 9/20/87
  1664. X.\"
  1665. X.lt 6.0i
  1666. X.TH SPIFF 1 "February 2, 1988"
  1667. X.AT 3
  1668. X.SH NAME
  1669. Xspiff \- make controlled approximate comparisons between files 
  1670. X.SH SYNOPSIS
  1671. X.B spiff
  1672. X[
  1673. X.B \-s
  1674. Xscript ] [
  1675. X.B \-f
  1676. Xsfile ] [
  1677. X.B \-bteviqcdwm
  1678. X] [
  1679. X.B \-a
  1680. X\(br
  1681. X.B \-r
  1682. Xvalue ] \-value file1 file2
  1683. X.SH DESCRIPTION
  1684. X.I Spiff
  1685. Xcompares the contents of 
  1686. X.B file1
  1687. Xand
  1688. X.B file2
  1689. Xand prints a description of the important differences between
  1690. Xthe files.
  1691. XWhite space is ignored except to separate other objects.
  1692. X.I Spiff
  1693. Xmaintains tolerances below which differences between two floating point
  1694. Xnumbers are ignored. 
  1695. XDifferences in floating point notation (such as 3.4 3.40 and 3.4e01)
  1696. Xare treated as unimportant.
  1697. XUser specified delimited strings (i.e. comments) can also be ignored.
  1698. XInside other user specified delimited strings
  1699. X(i.e. quoted strings) whitespace can be significant.
  1700. X.PP
  1701. X.I Spiff's
  1702. Xoperation can be altered via command line options, a command script, and with
  1703. Xcommands that are embedded in the input files.
  1704. X.PP
  1705. XThe following options affect
  1706. X.I spiff's
  1707. Xoverall operation.
  1708. X.TP
  1709. X.B \-q
  1710. Xsuppresses warning messages.
  1711. X.TP
  1712. X.B \-v
  1713. Xuse a visually oriented display.  Works only in MGR windows.
  1714. X.PP
  1715. X.I Spiff
  1716. Xhas several flags to aid differencing of various programming languages.
  1717. XSee EXAMPLES for a detailed description of the effects of these flags.
  1718. X.TP
  1719. X.B \-C
  1720. Xtreat the input files as C program source code.
  1721. X.TP
  1722. X.B \-S
  1723. Xtreat the input files as Bourne shell program source code.
  1724. X.TP
  1725. X.B \-F
  1726. Xtreat the input files as Fortran program source code.
  1727. X.TP
  1728. X.B \-M
  1729. Xtreat the input files as Modula-2 program source code.
  1730. X.TP
  1731. X.B \-L
  1732. Xtreat the input files as Lisp program source code.
  1733. X.PP
  1734. XBy default, the output looks somewhat similar in appearance
  1735. Xto the output of diff(1).  Lines with differences are printed with
  1736. Xthe differences highlighted.  If stdout is a terminal, as determined
  1737. Xby isatty(), then highlighting uses standout mode as determined by termcap.
  1738. XIf stdout is not a tty, then the underlining (via underscore/backspace/char)
  1739. Xis used to highlight differences.
  1740. XThe following option can control the format of the ouput.
  1741. X.TP
  1742. X.B \-t
  1743. Xproduce output in terms of individual tokens.  This option is
  1744. Xmost useful for debugging as the output produced is verbose to
  1745. Xthe point of being unreadable.
  1746. X.PP
  1747. XThe following option controls the differencing algorithm.
  1748. X.TP
  1749. X.B \-e
  1750. Xcompare each token 
  1751. Xin the files with the object in the same ordinal
  1752. Xposition in the other file.  If the files have a different number
  1753. Xof objects, a warning message is printed
  1754. Xand the objects at the end of the longer file are ignored.
  1755. XBy default,
  1756. X.I spiff
  1757. Xuses a Miller/Myers algorithm to find a minimal edit sequence
  1758. Xthat will convert the contents of the first file into the second.
  1759. X.TP
  1760. X\-<decimal-value>
  1761. Xsets a limit on the total number of insertions and deletions
  1762. Xthat will be considered.
  1763. XIf the files differ by more than the stated amount,
  1764. Xthe program will give up, print a warning message, and exit.
  1765. X.PP
  1766. XThe following options control the command script.  More than one of
  1767. Xeach may appear at at time. The commands accumulate.
  1768. X.TP
  1769. X.B \-f sfile
  1770. Xa command script to be taken from file
  1771. X.IR sfile 
  1772. X.TP
  1773. X.B \-s command-script
  1774. Xcauses the following argument to be taken as a command script.
  1775. X.PP
  1776. XThe following options control how individual objects are compared.
  1777. X.TP
  1778. X.B \-b
  1779. Xtreat all objects (including floating point numbers) as literals.
  1780. X.TP
  1781. X.B \-c
  1782. Xignore differences between upper and lower case.
  1783. X.PP
  1784. XThe following commands will control how the files are parsed.
  1785. X.TP
  1786. X.B \-w
  1787. Xtreat white space as objects.  Each white space character will
  1788. Xbe treated as a separate object when the program is comparing the
  1789. Xfiles.
  1790. X.TP
  1791. X.B \-m
  1792. Xtreat leading sign characters ( + and \- ) as separate even
  1793. Xif they are followed by floating point numbers.
  1794. X.TP
  1795. X.B \-d
  1796. Xtreat integer decimal numbers (such as 1987) as real numbers (subject to
  1797. Xtolerances) rather than as literal strings.
  1798. X.PP
  1799. XThe following three flags are used to set the default tolerances.
  1800. XThe floating-point-numbers may be given in the formats accepted
  1801. Xby atof(3).
  1802. X.TP
  1803. X.B \-a floating-point-number
  1804. Xspecifies an absolute value for the tolerance in floating point numbers.
  1805. XThe flag
  1806. X.B \-a1e-2
  1807. Xwill cause all differences greater than 0.01 to be reported.
  1808. X.TP
  1809. X.B \-r floating-point-number
  1810. Xspecifies a relative tolerance. The value given is interpreted
  1811. Xas a fraction of the larger (in absolute terms) 
  1812. Xof the two floating point numbers being compared.
  1813. XThus, the flag
  1814. X.B \-r0.1
  1815. Xwill cause the two floating point numbers 1.0 and 0.9 to be deemed within
  1816. Xtolerance. The numbers 1.0 and 0.89 will be outside the tolerance.
  1817. X.TP
  1818. X.B \-i
  1819. Xcauses differences between floating point numbers to be ignored.
  1820. X.PP
  1821. XIf more than one
  1822. X.B \-a, \-r,
  1823. Xor
  1824. X.B \-i
  1825. Xflag appear on the command line,
  1826. Xthe tolerances will be OR'd together (i.e. any difference that is within
  1827. Xany of the tolerances will be ignored). 
  1828. X.PP
  1829. XIf no default tolerances is set on the command line,
  1830. Xthe program will use a default tolerance of
  1831. X.B '\-a 1e-10 \-r 1e-10'.
  1832. X.SH SCRIPT COMMANDS
  1833. X.PP
  1834. XA script consists of commands, one per line.
  1835. XEach command consists of a keyword possibly followed by arguments.
  1836. XArguments are separated by one or more tabs or spaces.
  1837. XThe commands are:
  1838. X.TP
  1839. Xliteral BEGIN-STRING [END-STRING [ESCAPE-STRING]]
  1840. XSpecifies the delimiters surrounding text that is to be treated as a single
  1841. Xliteral object. If only one argument is present, then only that string itself is treated
  1842. Xas a literal. If only two arguments are present, they are taking as the starting
  1843. Xand ending delimiters respectively.  If three arguments are present, they are treated
  1844. Xas the start delimiter, end delimiter, and a string that may be used to escape
  1845. Xan instance of the end delimiter.
  1846. X.TP
  1847. Xbeginchar BEGINNING-OF-LINE-CHARACTER
  1848. XSet the the beginning of line character for BEGIN-STRING's in comments.
  1849. XThe default is '^'.
  1850. X.TP
  1851. Xendchar END-OF-LINE-CHARACTER
  1852. XSet the end of line character for END-STRING's in comments.
  1853. XThe default is '$'.
  1854. X.TP
  1855. Xaddalpha NEW-ALPHA-CHARACTER
  1856. XAdd NEW-ALPHA-CHARACTER to the set of characters allowed in literal strings.
  1857. XBy default, 
  1858. X.I spiff
  1859. Xparses sequences of characters that begin with a letter and followed by
  1860. Xzero or more letters or numbers as a single literal token.  This definition
  1861. Xis overly restrictive when dealing with programming languages.
  1862. XFor example, in the C programming language,
  1863. Xthe underscore character is allowed in identifiers. 
  1864. X.TP
  1865. Xcomment BEGIN-STRING [END-STRING [ESCAPE-STRING]]
  1866. XSpecifies the delimiters surrounding text that is to be be ignored entirely
  1867. X(i.e. viewed as comments).
  1868. XThe operation of the comment command is very similar to the literal command.
  1869. XIn addition, if the END-STRING consists of only
  1870. Xthe end of line character, the end of line will delimit the end of the comment.
  1871. XAlso, if the BEGIN-STRING starts with the beginning of line character, only
  1872. Xlines that begin with the BEGIN-STRING will be ignored.
  1873. X.PP
  1874. XMore than one comment specification and more than one literal string specification
  1875. Xmay be specified at a time.
  1876. X.TP
  1877. Xnestcom BEGIN-STRING [END-STRING [ESCAPE-STRING]]
  1878. XSimilar to the comment command, but allows comments to be nested.
  1879. XNote, due to the design of the parser nested comments can not
  1880. Xhave a BEGIN-STRING that starts with the beginning of line character.  
  1881. X.TP
  1882. Xresetcomments
  1883. XClears the list of comment specifications.
  1884. X.TP
  1885. Xresetliterals
  1886. XClears the list of literal specifications.
  1887. X.TP
  1888. Xtol [aVALUE\(brrVALUE\(bri\(brd . . . [ ; aVALUE\(brrVALUE\(bri\(brd . . . ] . . . ]
  1889. Xset the tolerance for floating point comparisons.  
  1890. XThe arguments to the tol command are a set of tolerance specifications
  1891. Xseparated by semicolons.  If more than one a,r,d, or i appears within
  1892. Xa specification, then the tolerances are OR'd together (i.e. any difference
  1893. Xthat is within any tolerance will be ignored).
  1894. XThe semantics of a,r, and i are identical to the
  1895. X.B \-a, \-r,
  1896. Xand
  1897. X.B \-i
  1898. Xflags. The d means that the default tolerance (as specified by the invocation
  1899. Xoptions) should be used.
  1900. XIf more than one specification appears on the line, the first
  1901. Xspecification is applied to the first floating point number on each line,
  1902. Xthe second specification to the second floating point number one each line
  1903. Xof the input files, and so on.  If there are more floating point numbers
  1904. Xon a given line of input than tolerance specifications,
  1905. Xthe last specification is used repeatedly for all remaining floating point numbers
  1906. Xon that line.
  1907. X.TP
  1908. Xcommand STRING
  1909. Xlines in the input file that start with STRING will be interpreted as
  1910. Xcommand lines. If no "command" is given as part of a
  1911. X.B \-s
  1912. Xor
  1913. X.B \-f
  1914. Xthen it will be impossible to embed commands in the input files.
  1915. X.TP
  1916. Xrem
  1917. X.TP
  1918. X#
  1919. Xused to places human readable remarks into a commands script. Note that the
  1920. Xuse of the '#' character differs from other command languages (for instance
  1921. Xthe Bourne shell).
  1922. X.I Spiff
  1923. Xwill only recognize the '#' as beginning a comment when it is the first
  1924. Xnon-blank character on the command line.  A '#' character appearing elsewhere
  1925. Xwill be treated as part of the command.  Cautious users should use 'rem'.
  1926. XThose hopelessly addicted to '#' as a comment character can have command
  1927. Xscripts with a familiar format.
  1928. X.PP
  1929. XTolerances specified in the command scripts have precedence over the tolerance
  1930. Xspecified on the invocation command line. The tolerance specified in
  1931. X.I file1
  1932. Xhas precedence over the tolerance specified in
  1933. X.I file2.
  1934. X.PP
  1935. X.SH VISUAL MODE
  1936. XIf
  1937. X.I spiff
  1938. Xis invoked with the \-v option, it will enter an interactive mode rather
  1939. Xthan produce an edit sequence.  Three windows will be put on the screen.
  1940. XTwo windows will contain corresponding segments of the input files.
  1941. XObjects that appear in both segments will be examined for differences and
  1942. Xif any difference is found, the objects will be highlighted in reverse video
  1943. Xon the screen.  Objects that appear in only one window will have a line drawn
  1944. Xthrough them to indicate that they aren't being compared with anything in the other
  1945. Xtext window. The third window is a command window.  The command window will
  1946. Xaccept a single tolerance specification (followed by a newline)
  1947. Xin a form suitable to the
  1948. X.B tol
  1949. Xcommand.  The tolerance specified will then be used as the default tolerance
  1950. Xand the display will be updated to highlight only those objects that exceed
  1951. Xthe new default tolerance.  Typing 
  1952. X.B m
  1953. X(followed by a newline) will display the next screenfull of text. Typing
  1954. X.B q
  1955. X(followed by a newline)  will cause the program to exit.
  1956. X.SH LIMITS
  1957. XEach input files can be no longer that 10,000 line long or contain more
  1958. Xthan 50,000 tokens. Longer files will be truncated.
  1959. XNo line can be longer than 1024 characters.  Newlines
  1960. Xwill be inserted every 1024 character.
  1961. X.SH EXAMPLES
  1962. X.TP
  1963. Xspiff \-e \-d foo bar
  1964. Xthis invocation (using exact match algorithm and treating integer numbers
  1965. Xas if they were floats) is very useful for examining large tables of numbers.
  1966. X.TP
  1967. Xspiff \-0 foo bar
  1968. Xcompare the two files, quitting after the first difference is found.
  1969. XThis makes the program operate roughly like cmp(1).
  1970. X.TP
  1971. Xspiff \-0 -q foo bar
  1972. Xsame as the above, but no output is produced.
  1973. XThe return code is still useful.
  1974. X.TP
  1975. Xspiff \-w \-b foo bar
  1976. Xwill make the program operate much like diff(1).
  1977. X.TP
  1978. Xspiff \-a1e-5 \-r0.001 foo bar
  1979. Xcompare the contents of the files foo and bar and ignore all differences between
  1980. Xfloating point numbers that are less than or equal to
  1981. X0.00001 or 0.1% of the number of larger magnitude.
  1982. X.TP
  1983. Xtol a.01 r.01
  1984. Xwill cause all differences between floating point numbers that are less than
  1985. Xor equal to
  1986. X0.01 or 1% of the number of larger magnitude to be ignored.
  1987. X.TP
  1988. Xtol a.01 r.01 ; i
  1989. Xwill cause the tolerance in the previous example to be applied to the first
  1990. Xfloating point number on each line.  All differences between the second and
  1991. Xsubsequent floating point numbers on each line will be ignored.
  1992. X.TP
  1993. Xtol a.01 r.01 ; i ; a.0001
  1994. Xlike the above except that only differences between the second floating point
  1995. Xnumber on each line will be ignored. The differences between
  1996. Xthird and subsequent floating point numbers on each number will be ignored if they
  1997. Xare less than or equal to 0.0001.
  1998. X.IP
  1999. XA useful script for examing C code is:
  2000. X.nf
  2001. Xliteral  "    "    \\ 
  2002. Xcomment  /*  */
  2003. Xliteral  &&
  2004. Xliteral  \(br\(br
  2005. Xliteral  <=
  2006. Xliteral  >=
  2007. Xliteral  !=
  2008. Xliteral  ==
  2009. Xliteral  --
  2010. Xliteral  ++
  2011. Xliteral  <<
  2012. Xliteral  >>
  2013. Xliteral  ->
  2014. Xaddalpha _
  2015. Xtol      a0
  2016. X.fi
  2017. X.IP
  2018. XA useful script for shell programs is:
  2019. X.nf
  2020. Xliteral  '    '    \\
  2021. Xcomment  #    $
  2022. Xtol      a0
  2023. X.fi
  2024. X.IP
  2025. XA useful script for Fortran programs is:
  2026. X.nf
  2027. Xliteral ' ' '
  2028. Xcomment ^C $
  2029. Xtol     a0
  2030. X.fi
  2031. X.IP
  2032. XA useful script for Modula 2 programs is:
  2033. X.nf
  2034. Xliteral ' '
  2035. Xliteral " "
  2036. Xnestcom (* *)
  2037. Xliteral :=
  2038. Xliteral <>
  2039. Xliteral <=
  2040. Xliteral >=
  2041. Xtol     a0
  2042. X.fi
  2043. X.IP
  2044. XA useful script for Lisp programs is:
  2045. X.nf
  2046. Xliteral " "
  2047. Xcomment ; $
  2048. Xtol     a0
  2049. X.fi
  2050. X.SH DIAGNOSTICS
  2051. X.I Spiff's
  2052. Xexit status is 0 if no differences are found, 1 if differences are found, and
  2053. X2 upon error.
  2054. X.SH BUGS
  2055. XIn C code, escaped newlines will appear as differences.
  2056. X.PP
  2057. XComments are treated as token delimiters.
  2058. X.PP
  2059. XComments in Basic don't work right.  The line number is not ignored.
  2060. X.PP
  2061. XContinuation lines in Fortran comments don't work.
  2062. X.PP
  2063. XThere is no way to represent strings specified using a
  2064. XHollerith notation in Fortran.
  2065. X.PP
  2066. XIn formated English text, hyphenated words,
  2067. Xmovements in pictures, footnotes, etc.
  2068. Xwill be reported as differences.
  2069. X.PP
  2070. XSTRING's in script commands can not include whitespace.
  2071. X.PP
  2072. XVisual mode does not handle tabs properly.  Files containing
  2073. Xtabs should be run through
  2074. Xexpand(1) before trying to display them with visual mode.
  2075. X.PP
  2076. XIn visual mode, the text windows appear in a fixed size and font.
  2077. XLines longer than the window size will not be handled properly.
  2078. X.PP
  2079. XObjects (literal strings) that contain newlines cause trouble in several places
  2080. Xin visual mode.
  2081. X.PP
  2082. XVisual mode should accept more than one tolerance specification.
  2083. X.PP
  2084. XWhen using visual mode or the exact match comparison algorithm, the program
  2085. Xshould do the parsing on the fly rather than truncating long files.
  2086. X.SH AUTHOR
  2087. XDaniel Nachbar
  2088. X.SH COPYRIGHT
  2089. X.nf
  2090. X                 Copyright (c) 1988 Bellcore
  2091. X                     All Rights Reserved
  2092. XPermission is granted to copy or use this program,
  2093. XEXCEPT that it may not be sold for profit, the copyright
  2094. Xnotice must be reproduced on copies, and credit should
  2095. Xbe given to Bellcore where it is due.
  2096. X         BELLCORE MAKES NO WARRANTY AND ACCEPTS
  2097. X            NO LIABILITY FOR THIS PROGRAM.
  2098. X.fi
  2099. X
  2100. X.br
  2101. X.SH SEE ALSO
  2102. Xatof(3)
  2103. Xisatty(2)
  2104. Xdiff(1)
  2105. Xcmp(1)
  2106. Xexpand(1)
  2107. Xmgr(1L)
  2108. X.PP
  2109. X"Spiff -- A Program for Making Controlled Approximate Comparisons of Files",
  2110. Xby Daniel Nachbar.
  2111. X.PP
  2112. X"A File Comparison Program" by Webb Miller and Eugene W. Myers in Software \-
  2113. XPractice and Experience, Volume 15(11), pp.1025-1040, (November 1985).
  2114. END_OF_FILE
  2115. if test 14738 -ne `wc -c <'spiff.1'`; then
  2116.     echo shar: \"'spiff.1'\" unpacked with wrong size!
  2117. fi
  2118. # end of 'spiff.1'
  2119. fi
  2120. echo shar: End of archive 3 \(of 4\).
  2121. cp /dev/null ark3isdone
  2122. MISSING=""
  2123. for I in 1 2 3 4 ; do
  2124.     if test ! -f ark${I}isdone ; then
  2125.     MISSING="${MISSING} ${I}"
  2126.     fi
  2127. done
  2128. if test "${MISSING}" = "" ; then
  2129.     echo You have unpacked all 4 archives.
  2130.     rm -f ark[1-9]isdone
  2131. else
  2132.     echo You still need to unpack the following archives:
  2133.     echo "        " ${MISSING}
  2134. fi
  2135. ##  End of shell archive.
  2136. exit 0
  2137.